# -*- coding:UTF-8 -*-

import cv2
import win32gui
import win32ui
import win32con
import win32api
import numpy
import random
from datetime import datetime


screenScale = 1

windowH = 0
windowW = 0
hwnd = 0


def sleep_ad(num, randomNum=0):
    """
    使程序休眠指定的时间。

    参数：
    num (int): 休眠的秒数。
    randomNum (int, 可选): 随机数的范围。默认为0。

    返回：
    无。

    示例：
    >>> sleepAd(2)
    >>> sleepAd(3, 5)
    """

    win32api.Sleep(int(num*1000+random.random()*randomNum*1000))


def click_rect(hwnd, screen, scale_x, scale_y, scale_x_num=0, scale_y_num=0, t=120):
    """
    这是一个用于在给定屏幕区域内查找图像的函数。

    参数:

    hwnd: 窗口
    x,y: 点击坐标中心比例
    num: 偏移值比例
    t: 按下时间。毫秒，最大300
    返回:无
    """
    x = int(screen['width']*scale_x)
    y = int(screen['height']*scale_y)
    x_num = int(screen['width']*scale_x_num)
    y_num = int(screen['height']*scale_y_num)
    sign_x = random.choice([-1, 1])
    offsetX, offsetY = sign_x * random.random() * (x_num/2), sign_x * \
        random.random() * (y_num/2)
    clickX, clickY = int(
        x + offsetX), int(y + offsetY)

    # 模拟鼠标点击
    longPosition = win32api.MAKELONG(clickX, clickY)
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, longPosition)
    win32api.Sleep(120 + int(random.random() * t))
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, longPosition)

    # 写入日志
    print(f'{datetime.now()}--点击：cx{clickX}, cy{clickY}, {t}')


def click_right(hwnd, x, y, x_num=20, y_num=20, t=140):
    """
    这是一个用于在给定屏幕区域内查找图像的函数。

    参数:

    hwnd: 窗口
    x,y: 点击坐标
    num: 偏移值
    t: 按下时间。毫秒，最大300
    返回:无
    """
    sign_x = random.choice([-1, 1])

    offsetX, offsetY = sign_x * random.random() * (x_num/2), sign_x * \
        random.random() * (y_num/2)
    clickX, clickY = int(
        x + offsetX), int(y + offsetY)

   # 模拟鼠标右键点击
    longPosition = win32api.MAKELONG(clickX, clickY)
    win32api.SendMessage(hwnd, win32con.WM_RBUTTONDOWN,
                         win32con.MK_RBUTTON, longPosition)
    win32api.Sleep(80 + int(random.random() * t))
    win32api.SendMessage(hwnd, win32con.WM_RBUTTONUP,
                         win32con.MK_RBUTTON, longPosition)

    # 写入日志
    print(f'{datetime.now()}--右键点击：cx{clickX}, cy{clickY}, {t}')


def double_click(hwnd, x, y, x_num=20, y_num=20, t=140):
    """
    这是一个用于在给定屏幕区域内查找图像的函数。

    参数:

    hwnd: 窗口
    x,y: 点击坐标
    num: 偏移值
    t: 按下时间。毫秒，最大300
    返回:无
    """
    sign_x = random.choice([-1, 1])
    offsetX, offsetY = sign_x * random.random() * (x_num/2), sign_x * \
        random.random() * (y_num/2)
    clickX, clickY = int(
        x + offsetX), int(y + offsetY)

    # 模拟鼠标点击
    longPosition = win32api.MAKELONG(clickX, clickY)
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, longPosition)
    win32api.Sleep(80 + int(random.random() * t))
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, longPosition)

    win32api.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, longPosition)
    win32api.Sleep(80 + int(random.random() * t))
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, longPosition)

    # 写入日志
    print(f'{datetime.now()}--双击：cx{clickX}, cy{clickY}, {t}')


def click(hwnd, x, y, x_num=20, y_num=20, t=120):
    """
    这是一个用于在给定屏幕区域内查找图像的函数。

    参数:

    hwnd: 窗口
    x,y: 点击坐标
    num: 偏移值
    t: 按下时间。毫秒，最大300
    返回:无
    """
    sign_x = random.choice([-1, 1])
    offsetX, offsetY = sign_x * random.random() * (x_num/2), sign_x * \
        random.random() * (y_num/2)
    clickX, clickY = int(
        x + offsetX), int(y + offsetY)

    # 模拟鼠标点击
    longPosition = win32api.MAKELONG(clickX, clickY)
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, longPosition)
    win32api.Sleep(120 + int(random.random() * t))
    win32api.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, longPosition)

    # 写入日志
    print(f'{datetime.now()}--点击：cx{clickX}, cy{clickY}, {t}')


def window_screenshot(e):
    """
    该函数用于截取指定窗口的屏幕截图。

    参数:
    e: 要截取的窗口句柄

    返回值:
    data: 包含截图信息的字典，包括左边距(left)、上边距(top)、高度(height)、宽度(width)和截图保存路径(path)

    注释:
    - 代码主要使用了win32gui、win32ui和cv2等库进行窗口截图和图像处理。
    - 首先获取窗口的位置和大小，并创建设备描述表和内存设备描述表。
    - 然后创建位图对象，并将截图保存到位图对象中。
    - 接下来获取位图信息，并将其转换为图片文件保存。
    - 最后返回截图信息。

    请在调用该函数前确保已导入所需的库，并传入正确的窗口句柄作为参数。
    """
    global windowH, windowW, hwnd
    hwnd = e
    # 获取窗口句柄
    left, top, right, bot = win32gui.GetWindowRect(e)
    width, height = right - left, bot - top
    windowH, windowW = height, width

    # 获取句柄窗口的设备环境
    hWndDC = win32gui.GetWindowDC(e)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 为bitmap开辟存储空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
    # 将截图保存到saveBitMap中
    saveDC.SelectObject(saveBitMap)
    # 保存bitmap到内存设备描述表
    saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)

    # 获取位图信息并释放内存
    signedIntsArray = saveBitMap.GetBitmapBits(True)
    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(e, hWndDC)

    # 将位图信息转为图片文件并保存
    img = numpy.frombuffer(signedIntsArray, dtype='uint8')
    img.shape = (height, width, 4)
    cv2.cvtColor(img, cv2.COLOR_BGRA2RGB)
    cv2.imwrite(f'img_{e}.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), 100])

    # 返回截图信息
    data = {
        'left': left,
        'top': top,
        'height': height,
        'width': width,
        'path': f'img_{e}.jpg'
    }

    return data


def find_scale_img(targetPath, standard_value, screen, num=0.66, x=0, x1=1, y=0, y1=1):

    temp = cv2.imread(screen['path'], cv2.IMREAD_GRAYSCALE)
    tempheight, tempwidth = temp.shape[0:2]

    screenScale = tempwidth/standard_value
    print(screenScale)
    # 先缩放屏幕截图 INTER_LINEAR INTER_AREA
    scaleTemp = cv2.resize(
        temp, (int(tempwidth * screenScale), int(tempheight * screenScale)))
    # print(temp.shape)  # 这里会返回三个值 （673,1084,3）图片的高，图片的宽，色彩通道
    cx = int(x*windowW * screenScale)
    cx1 = int(x1*windowW * screenScale)
    cy = int(y*windowH * screenScale)
    cy1 = int(y1*windowH * screenScale)
    cropped = scaleTemp[cy:cy1, cx:cx1]  # 开始的y坐标:结束的y坐标,开始x:结束的x
    img = numpy.frombuffer(numpy.ascontiguousarray(cropped), dtype='uint8')
    img.shape = (cy1-cy, cx1-cx)
    cv2.cvtColor(img, cv2.COLOR_BGRA2RGB)
    cv2.imwrite('img_findImg55.jpg', img,
                [int(cv2.IMWRITE_JPEG_QUALITY), 100])
    # # 读取匹配图片
    target = cv2.imread(targetPath, cv2.IMREAD_GRAYSCALE)
    theight, twidth = target.shape[0:2]
    # 匹配图片
    res = cv2.matchTemplate(cropped, target, cv2.TM_CCOEFF_NORMED)
    mn_val, max_val, min_loc, max_loc = cv2.minMaxLoc(
        res)  # 开始的y坐标:结束的y坐标,开始x:结束的x

    data = {}
    data['max_val'] = max_val
    if (max_val >= num):
        # 计算出中心点
        top_left = max_loc
        tagHalfW = int(twidth/2)
        tagHalfH = int(theight/2)
        # 计算中心点要考虑截屏的偏移量
        tagCenterX = int(top_left[0]+tagHalfW+cx)
        tagCenterY = int(top_left[1]+tagHalfH+cy)
        data["isFind"] = True
        data["x"] = tagCenterX
        data["y"] = tagCenterY
        (xa, xb) = max_loc
        startX = xa+cx
        startY = xb+cy
        endX = startX + twidth
        endY = startY + theight
        data['startX'] = startX
        data['endX'] = endX
        data['startY'] = startY
        data['endY'] = endY

    else:
        data["isFind"] = False
        data["x"] = 0
        data["y"] = 0
    print(f'{str(datetime.now())}--查图：{str(targetPath)},{str(data)}')

    return data


'''
禁止点击区域判断
no_cilck_arr为而为数组，分别是[[start_x,end_x,start_y,end_y]]
'''


def is_inside(screen, point, rectangles=[]):
    height = screen['height']
    width = screen['width']
    x, y = point
    for rect in rectangles:
        x_range = sorted([rect[0]*width, rect[1]*width])
        y_range = sorted([rect[2]*height, rect[3]*height])
        if x_range[0] <= x <= x_range[1] and y_range[0] <= y <= y_range[1]:
            print(f'{datetime.now()}--禁点区域：True，{rect},{x_range},{y_range}')
            return True
    print(f'{datetime.now()}--禁点区域：False')
    return False


'''
X,X1,Y,Y1是像素
'''


def clip(hwnd, screen, x=0, x1=0, y=0, y1=0):
    # 获取屏幕截图并缩放
    temp = cv2.imread(screen['path'], cv2.IMREAD_GRAYSCALE)
    tempHeight, tempWidth = temp.shape[0:2]
    scaleTemp = cv2.resize(
        temp, (int(tempWidth / screenScale), int(tempHeight / screenScale)))

    # 裁剪图片并保存到文件
    w, h = screen['width'], screen['height']
    if y1 > h:
        y1 = h
    cx1, cy1 = x1 or w, y1 or h
    cropped = scaleTemp[y:cy1, x:cx1]
    width, height = cx1 - x, cy1 - y
    img = numpy.frombuffer(numpy.ascontiguousarray(cropped), dtype='uint8')
    img.shape = (height, width)
    cv2.cvtColor(img, cv2.COLOR_BGRA2RGB)
    cv2.imwrite(f'img_clip_{hwnd}.jpg', img, [
                int(cv2.IMWRITE_JPEG_QUALITY), 100])
    data = {
        'left': x,
        'top': y,
        'path': f'img_clip_{hwnd}.jpg',
        'height': height,
        'width': width
    }
    print(f'{datetime.now()}--裁剪：{data}')
    return data


"""
这些函数依赖公共变量
"""


# 下滑

def swipe_down(hwnd, num=50):
    height = windowH
    width = windowW

    # 随机计算起始和结束位置偏移量
    offestX = int(random.random() * (width * 0.3) + (width * 0.3))
    offestY = int(random.random() * height *
                  0.08 + (height - 100) * 0.7)
    offestX1 = int(random.random() * (width * 0.3) + (width * 0.3))
    offestY1 = int(random.random() * height *
                   0.07 + (height - 100) * 0.23)

    # 开始模拟滑动操作
    startParam = win32api.MAKELONG(offestX1, offestY1)
    endParam = win32api.MAKELONG(offestX, offestY)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, startParam)
    clicks = offestY - offestY1
    clicksX = offestX - offestX1
    for i in range(5):
        nextY = offestY - int((clicks/5)*i)
        nextX = offestX - int((clicksX/5)*i)
        param = win32api.MAKELONG(nextX, nextY)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # 加上间隔时间
        win32api.Sleep(num)

    # 模拟鼠标抬起
    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, endParam)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, endParam)

    # 写入日志
    print(f'{datetime.now()}--下滑：[{offestX1, offestY1}], [{offestX, offestY}]')
    with open('日志.txt', 'a', encoding='utf-8') as f:
        f.write(
            f'{datetime.now()}--下滑：[{offestX1, offestY1}], [{offestX, offestY}]\n')

# 上滑


def swipe_up(hwnd, num=50):
    height = windowH
    width = windowW

    # 随机计算起始和结束位置偏移量
    offestX = int(random.random()*(width*0.4)+(width*0.1))
    offestY = int(random.random()*height*0.2+(height)*0.8)-80

    offestX1 = offestX - int(random.random()*(width*0.25))

    offestY1 = int(
        offestY-(height*0.3+random.random()*height*0.25))

    # 开始模拟滑动操作
    startParam = win32api.MAKELONG(offestX, offestY)
    endParam = win32api.MAKELONG(offestX1, offestY1)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, startParam)
    clicks = offestY - offestY1
    clicksX = offestX - offestX1
    for i in range(10):
        nextY = offestY - int((clicks/10)*i)
        nextX = offestX - int((clicksX/10)*i)
        param = win32api.MAKELONG(nextX, nextY)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # 加上间隔时间
        win32api.Sleep(num)

    # 模拟鼠标抬起
    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, endParam)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, endParam)

    # 写入日志
    print(f'{datetime.now()}--长滑：[{offestX, offestY}], [{offestX1, offestY1}]')
    with open('日志.txt', 'a', encoding='utf-8') as f:
        f.write(
            f'{datetime.now()}--长滑：[{offestX, offestY}], [{offestX1, offestY1}]\n')


def duan_swiper(hwnd, num=50, Y=110):
    height = windowH
    width = windowW

    # 随机计算起始位置偏移量
    offestY = int(random.random() * (height - 100)
                  * 0.1 + (height - 100) * 0.60)
    offestY1 = offestY - Y
    offestX = int(random.random() * (width * 0.3) + (width * 0.3))

    # 开始模拟滑动操作
    startParam = win32api.MAKELONG(offestX, offestY)
    endParam = win32api.MAKELONG(offestX, offestY1)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, startParam)
    clicks = offestY - offestY1
    for i in range(5):
        nextY = offestY - int((clicks/5)*i)
        param = win32api.MAKELONG(offestX, nextY)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # 加上间隔时间
        win32api.Sleep(num)

    # 模拟鼠标抬起
    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, endParam)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, endParam)

    # 写入日志
    print(f'{datetime.now()}--短滑：[{offestX, offestY}], [{offestX, offestY1}]')


def left_swiper(hwnd, num=50):
    height = windowH
    offestX = int(0)
    offestY = int(random.random()*height*0.2+(height)*0.4)
    offestY1 = offestY

    offestX1 = 80+random.random()*80

    start_param = win32api.MAKELONG(offestX, offestY)
    end_param = win32api.MAKELONG(offestX1, offestY1)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, start_param)
    clicks = offestY - offestY1
    clicksX = offestX - offestX1
    for i in range(5):
        next = offestY - int((clicks/5)*i)
        nextX = offestX - int((clicksX/5)*i)
        param = win32api.MAKELONG(nextX, next)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # A sleep is required here, or the message does nothing.
        win32api.Sleep(num)

    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, end_param)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, end_param)
    print(
        f'{str(datetime.now())}-上滑：[{str(offestX),str(offestY)}],[{str(offestX1),str(offestY1)}]')


def calculate_other_leg(a, c):
    return int(numpy.sqrt(c**2 - a**2))


def wasd(hwnd, screen, scale_x=0.192, scale_y=0.622, direction='', scale_offest=0.081, t=500):
    height = screen['height']
    width = screen['width']
    offest = int(width*scale_offest+random.random()*40)
    start_x = int(width*scale_x)
    start_y = int(height*scale_y)

    end_x = start_x
    end_y = start_y

    if len(direction) == 0:

        offest_x = int(random.random()*offest)
        offest_y = offest
        if offest_x != 0:
            offest_y = calculate_other_leg(offest_x, offest)
        sign_x = random.choice([-1, 1])
        end_x = int(start_x+offest_x*sign_x)
        sign_y = random.choice([-1, 1])
        end_y = int(start_y+offest_y*sign_y)
    start_param = win32api.MAKELONG(start_x, start_y)
    end_param = win32api.MAKELONG(end_x, end_y)

    # 按下鼠标
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, start_param)

    # 根据值来判断移动方向

    a = 1 if end_x-start_x > 0 else -1
    b = 1 if end_y-start_y > 0 else -1
    print(offest, offest_x, offest_y, a, b)
    for i in range(max(offest_x, offest_y)):

        next_x = start_x + i*a
        next_y = start_y + i*b
        param = win32api.MAKELONG(next_x, next_y)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # A sleep is required here, or the message does nothing.
        win32api.Sleep(1)
    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, end_param)
    sleep_ad(0.25, 0.25)
    # 放开鼠标
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, end_param)


'''
刷视频

为防止检测，行为点更像人

offestX offestY 起始点
offestX1 offestY1 结束点

offestX1 根据offestX来得到
人的操作性行为比较固定
offestY offestY1 一般在屏幕下半区
'''


def swiper(hwnd, num=5):
    height = windowH
    width = windowW
    offestX = int(random.random()*(width*0.4)+(width*0.1))
    offestY = int(random.random()*height*0.2+(height)*0.8)-80

    offestX1 = offestX - int(random.random()*(width*0.2))

    offestY1 = int(
        offestY-(height*0.1+random.random()*height*0.25))

    start_param = win32api.MAKELONG(offestX, offestY)
    end_param = win32api.MAKELONG(offestX1, offestY1)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,
                         win32con.MK_LBUTTON, start_param)
    clicks = offestY - offestY1
    clicksX = offestX - offestX1
    for i in range(5):
        next = offestY - int((clicks/5)*i)
        nextX = offestX - int((clicksX/5)*i)
        param = win32api.MAKELONG(nextX, next)
        win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                             win32con.MK_LBUTTON, param)
        # A sleep is required here, or the message does nothing.
        win32api.Sleep(num)

    win32gui.SendMessage(hwnd, win32con.WM_MOUSEMOVE,
                         win32con.MK_LBUTTON, end_param)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP,
                         win32con.MK_LBUTTON, end_param)
    print(
        f'{str(datetime.now())}-上滑：[{str(offestX),str(offestY)}],[{str(offestX1),str(offestY1)}]')


if __name__ == '__main__':
    wasd(263186, screen={'height': 553, 'width': 983})
    print("我是DYutils模块文件")
else:
    print("我是DYutils模块文件")
